%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                               %
%                       Legal Notice                            %
%                                                               %
% This document is copyright (C) Olaf Kirch, okir@monad.swb.de  %
%                                                               %
% For copying conditions, please refer to the file COPYING.	%
%                                                               %
% The author is not liable for any damages, direct or indirect, %
% resulting from the use of information provided in this        %
% document.                                                     %
%                                                               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% When viewing this document with vi on an 80-columns screen,   %
% do a ':se nonumber' first.                                    %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                               %
%               S T A R T   O F   C H A P T E R                 %
%                                                               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\chapter{The Network File System}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{nfs}
\index{file sharing}
\index{remote!file access}
\index{Network File System|see {NFS}}
\index{NFS|(}

NFS, the network filesystem, is probably the most prominent network
services using RPC. It allows to access files on remote hosts in exactly
the same way as a user would access any local files. This is made
possible by a mixture of kernel functionality on the client side (that
uses the remote file system) and an NFS server on the server side (that
provides the file data).  This file access is completely transparent to
the client, and works across a variety of server and host architectures.


NFS offers a number of advantages:


\begin{itemize}
\item   Data accessed by all users can be kept on a central
        host, with clients mounting this directory at boot time. For
        example, you can keep all user accounts on one host, and have
        all hosts on your network mount \file{/home} from that host. If
        installed alongside with NIS, users can then log into any
        system, and still work on one set of files.

\item   Data consuming large amounts of disk space may be kept
        on a single host.  For example, all files and programs relating
        to \LaTeX{} and METAFONT could be kept and maintained in one
        place.

\item   Administrative data may be kept on a single host.
        No need to use \prog{rcp} anymore to install the same
        stupid file on 20 different machines.

\end{itemize}


\linux{} NFS is largely the work of Rick Sladkey,\footnote{
 Rick can be reached at \email{jrs@world.std.com}.
} who wrote the NFS kernel code and large parts of the NFS server. The
latter is derived from the \prog{unfsd} user-space NFS server originally
written by Mark Shand, and the \file{hnfs} Harris NFS server written by
Donald Becker.


\index{NFS!mounting a volume}
Let's have a look now at how NFS works: A client may request to mount a
directory from a remote host on a local directory just the same way it
can mount a physical device.  However, the syntax used to specify the
remote directory is different. For example, to mount \file{/home} from
host \host{vlager} to \file{/users} on \host{vale}, the administrator
would issue the following command on \host{vale}:\footnote{
 Note that you can omit the \option{-t nfs} argument, because
 \prog{mount} sees from the colon that this specifies an NFS
 volume.
}

\begin{tscreen}
 \# mount -t nfs vlager:/home /users
\end{tscreen}

\prog{mount} will then try to connect to the \prog{mountd} mount daemon
on \host{vlager} via RPC. The server will check if \host{vale} is
permitted to mount the directory in question, and if so, return it a
file handle. This file handle will be used in all subsequent requests to
files below \file{/users}.


\index{server!nfsd@\prog{nfsd}}
\index{nfsd@\prog{nfsd}}
When someone accesses a file over NFS, the kernel places an RPC call to
\prog{nfsd} (the NFS daemon) on the server machine. This call takes the
file handle, the name of the file to be accessed, and the user's user
and group id as parameters. These are used in determining access rights
to the specified file. In order to prevent unauthorized users from
reading or modifying files, user and group ids must be the same on both
hosts.


On most \unix{} implementations, the NFS functionality of both client
and server are implemented as kernel-level daemons that are started from
user space at system boot.  These are the NFS daemon (\prog{nfsd}) on
the server host, and the \emph{Block I/O Daemon} (\prog{biod}) running
on the client host. To improve throughput, \prog{biod} performs
asynchronous I/O using read-ahead and write-behind; also, several
\prog{nfsd} daemons are usually run concurrently.


The NFS implementation of \linux{} is a little different in that the
client code is tightly integrated in the virtual file system (VFS) layer
of the kernel and doesn't require additional control through
\prog{biod}. On the other hand, the server code runs entirely in user
space, so that running several copies of the server at the same time is
almost impossible because of the synchronization issues this would
involve. \linux{} NFS currently also lacks read-ahead and write-behind,
but Rick Sladkey plans to add this someday.\footnote{
  The problem with write-behind is that the kernel buffer cache is indexed
  by device/inode pairs, and therefore can't be used for NFS-mounted
  file systems.
}


\index{NFS!limitations}
\index{NFS!server}
The biggest problem with the \linux{} NFS code is that the \linux{}
kernel as of version 1.0 is not able to allocate memory in chunks bigger
than 4K; as a consequence, the networking code cannot handle datagrams
bigger than roughly 3500 bytes after subtracting header sizes etc. This
means that transfers to and from NFS daemons running on systems that use
large UDP datagrams by default (e.g. 8K on SunOS) need to be downsized
artificially. This hurts performance badly under some
circumstances.\footnote{
  As explained to me by Alan Cox:
  The NFS specification requires the server to flush each write to disk
  before it returns an acknowledgement. As BSD kernels are only capable
  of page-sized writes (4K), writing a 4 chunks of 1K each to a BSD-based
  NFS server results in 4 write operations of 4K each.
} This limit is gone in late \linux{}-1.1 kernels, and the client code
has been modified to take advantage of this.



\section{Preparing NFS}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{nfs.nfsd}

Before you can use NFS, be it as server or client, you must make sure
your kernel has NFS support compiled in.  Newer kernels have a simple
interface on the proc filesystem for this, the \file{/proc/filesystems}
file,  which you can display using \prog{cat}:


\begin{tscreen}
\begin{verbatim}
$ cat /proc/filesystems
	minix
	ext2
	msdos
nodev	proc
nodev	nfs
\end{verbatim}
\end{tscreen}


If \keyword{nfs} is missing from this list, then you have to compile
your own kernel with NFS enabled.  Configuring the kernel network
options is explained in section ``Kernel Configuration'' in
chapter~\ref{hardware}.


For older kernels prior to \linux~1.1, the easiest way to find out
whether your kernel has NFS support enabled is to actually try to
mount an NFS file system. For this, you could create a directory below
\file{/tmp}, and try to mount a local directory on it:


\begin{tscreen}
 \# mkdir /tmp/test \\
 \# mount localhost:/etc /tmp/test
\end{tscreen}


If this mount attempt fails with an error message saying ``\term{fs
type nfs no supported by kernel}'', you must make a new kernel with
NFS enabled.  Any other error messages are completely harmless, as
you haven't configured the NFS daemons on your host yet.




\section{Mounting an NFS Volume}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{nfs.mountd}
\index{remote!file system}
\index{mounting!an NFS volume}
\index{acessing!remote files}
\index{NFS!mounting a volume}

NFS volumes\footnote{
 One doesn't say file system, because these are not proper file systems.
} are mounted very much the way usual file systems are mounted. You invoke
\prog{mount} using the following syntax:


\begin{tscreen}
\# mount -t nfs \var{nfs\_volume local\_dir options} 
\end{tscreen}


\var{nfs\_volume} is given as \var{remote\_host}\file{:}\var{remote\_dir}.
Since this notation is unique to NFS file systems, you can leave out
the \option{-t nfs} option.


\index{fstab@\file{fstab}}
\index{fstab@\file{fstab}}
There are a number of additional options that you may specify to
\prog{mount} upon mounting an NFS volume. These may either be given
following the \option{-o} switch on the command line, or in the options
field of the \file{/etc/fstab} entry for the volume. In both cases,
multiple options are separated from each other by commas. Options
specified on the command line always override those given in the
\file{fstab} file.


A sample entry in \file{/etc/fstab} might be

\begin{tscreen}
\begin{verbatim}
# volume              mount point       type  options
news:/usr/spool/news  /usr/spool/news   nfs   timeo=14,intr
\end{verbatim}
\end{tscreen}


This volume may then be mounted using

\begin{tscreen}
\# mount news:/usr/spool/news
\end{tscreen}

In the absence of a \file{fstab} entry, NFS \prog{mount} invocations
look a lot uglier. For instance, suppose you mount your users' home
directories from a machine named \host{moonshot}, which uses a default
block size of 4K for read/write operations. You might decrease
block size to 2K to suit \linux' datagram size limit by issuing


\begin{tscreen}
\# mount moonshot:/home /home -o rsize=2048,wsize=2048
\end{tscreen}


\index{NFS!restricting block size}
The list of all valid options is described in its entirety in the
\file{nfs(5)} manual page that comes with Rick Sladkey's NFS-aware
\prog{mount} tool which can be found in Rik Faith's \file{util-linux}
package).  The following is an incomplete list of those you would
probably want to use:

\begin{dispitems}
 \ditem[\keyword{rsize=}\var{n} and \keyword{wsize=}\var{n}]
        These specify the datagram size used by the NFS clients on
        read and write requests, respectively. They currently default
        to 1024 bytes, due to the limit on UDP datagram size described
        above.

 \ditem[\keyword{timeo=}\var{n}]
        This sets the time (in tenths of a second) the NFS client will
        wait for a request to complete. The default values is 0.7 seconds.

 \ditem[\keyword{hard}]
        Explicitly mark this volume as hard-mounted. This is on
        by default.

 \ditem[\keyword{soft}]
        Soft-mount the driver (as opposed to hard-mount).

 \ditem[\keyword{intr}]
        Allow signals to interrupt an NFS call. Useful for aborting
        when the server doesn't respond.

\end{dispitems}



Except for \keyword{rsize} and \keyword{wsize}, all of these options
apply to the client's behavior if the server should become inaccessible
temporarily. They play together in the following way: whenever the
client sends a request to the NFS server, it expects the operation to
have finished after a given interval (specified in the \keyword{timeout}
option). If no confirmation is received within this time, a so-called
\emph{minor timeout} occurs, and the operation is retried with the
timeout interval doubled. After reaching a maximum timeout of 60
seconds, a \emph{major timeout} occurs.


\index{NFS!hard-mounting vs. soft-mounting}
\index{NFS!timeout}
By default, a major timeout will cause the client to print a message to
the console and start all over again, this time with an initial timeout
interval twice that of the previous cascade. Potentially, this may go on
forever. Volumes that stubbornly retry an operation until the server
becomes available again are called \emph{hard-mounted}. The opposite
variety, \emph{soft-mounted} volumes gerenates an I/O error for the
calling process whenever a major timeout occurs. Because of the
write-behind introduced by the buffer cache, this error condition is not
propagated to the process itself before it calls the \func{write(2)}
function the next time, so a program can never be sure that a write
operation to a soft-mounted volume has succeded at all.


Whether you hard- or soft-mount a volume is not simply a question of
taste, but also has to do with what sort of information you want to
access from this volume. For example, if you mount your X~programs by
NFS, you certainly would not want your X~session to go berserk just
because someone brought the network to a grinding halt by firing up
seven copies of \prog{xv} at the same time, or by pulling the Ethernet
plug for a moment.  By hard-mounting these, you make sure that your
computer will wait until it is able to re-establish contact with your
NFS-server.  On the other hand, non-critical data such as NFS-mounted
news partititons or FTP archives may as well be soft-mounted, so it
doesn't hang your session in case the remote machine should be
temporarily unreachable, or down. If your network connection to the
server is flakey or goes through a loaded router, you may either
increase the initial timeout using the \keyword{timeo} option, or
hard-mount the volumes, but allow for signals interrupting the NFS call
so that you may still abort any hanging file access.


Usually, the \prog{mountd} daemon will in some way or other keep track
of which directories have been mounted by what hosts. This information
can be displayed using the \prog{showmount} program, which is also
included in the NFS server package. The \linux{} \prog{mountd}, however,
does not do this yet.




\section{The NFS Daemons}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{nfs.daemons}
\index{NFS!server}
\index{rc.inet@\file{rc.inet}}
\index{mountd@\prog{mountd}}
\index{nfsd@\prog{nfsd}}

If you want to provide NFS service to other hosts, you have to run the
\prog{nfsd} and \prog{mountd} daemons on your machine.  As RPC-based
programs, they are not managed by \prog{inetd}, but are started up at
boot time, and register themselves with the portmapper. Therefore, you
have to make sure to start them only after \prog{rpc.portmap} is
running.  Usually, you include the following two lines in your
\file{rc.inet2} script:


\begin{tscreen}
\begin{verbatim}
if [ -x /usr/sbin/rpc.mountd ]; then
        /usr/sbin/rpc.mountd; echo -n " mountd"
fi
if [ -x /usr/sbin/rpc.nfsd ]; then
        /usr/sbin/rpc.nfsd; echo -n " nfsd"
fi
\end{verbatim}
\end{tscreen}


\index{NFS!matching uids and gids}
The ownership information of files a NFS daemon provides to its
clients usually contains only numerical user and group id's.  If both
client and server associate the same user and group names with these
numerical id's, they are said to share the same uid/gid space. For
example, this is the case when you use NIS to distribute the
\file{passwd} information to all hosts on your LAN.


On some occasions, however, they do not match. Rather updating the
uid's and gid's of the client to match those of the server, you can
use the \prog{ugidd} mapping daemon to work around this. Using the
\keyword{map\_daemon} option explained below, you can tell \prog{nfsd}
to map the server's uid/gid space to the client's uid/gid space with
the aid of the \prog{ugidd} on the client.


\prog{ugidd} is an RPC-based server, and is started from
\file{rc.inet2} just like \prog{nfsd} and \prog{mountd}.


\begin{tscreen}
\begin{verbatim}
if [ -x /usr/sbin/rpc.ugidd ]; then
        /usr/sbin/rpc.ugidd; echo -n " ugidd"
fi
\end{verbatim}
\end{tscreen}



\section{The \file{exports} File}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{nfs.exports}
\index{NFS!exporting a volume}
\index{NFS!exports@\file{exports}}
\index{exporting an NFS volume}
\index{access!granting}
\index{mountd@\prog{mountd}}
\index{exports@\file{exports}}

While the above options applied to the client's NFS configuration,
there is a different set of options on the server side that configure
its per-client behavior. These options must be set in the
\file{/etc/exports} file.


By default, \prog{mountd} will not allow anyone to mount directories
from the local host, which is a rather sensible attitude. To permit
one or more hosts to NFS-mount a directory, it must \emph{exported}, that
is, must be specified in the \file{exports} file. A sample file may
look like this:


\begin{tscreen}
\begin{verbatim}
# exports file for vlager
/home             vale(rw) vstout(rw) vlight(rw)
/usr/X386         vale(ro) vstout(ro) vlight(ro)
/usr/TeX          vale(ro) vstout(ro) vlight(ro)
/                 vale(rw,no_root_squash)
/home/ftp         (ro)
\end{verbatim}
\end{tscreen}


Each line defines a directory, and the hosts allowed to mount it.  A
host name is usually a fully qualified domain name, but may additionally
contain the \keyword{*} and \keyword{?} wildcard, which act the way they
do with the Bourne shell. For instance, \host{lab*.foo.com} matches
\host{lab01.foo.com} as well as \host{laber.foo.com}.  If no host name
is given, as with the \file{/home/ftp} directory in the example above,
any host is allowed to mount this directory.


When checking a client host against the \file{exports} file,
\prog{mountd} will look up the client's hostname using the
\func{gethostbyaddr(2)} call. With DNS, this call returns the client's
canonical hostname, so you must make sure not to use aliases in
\file{exports}.  Without using DNS, the returned name is the first
hostname found in the \file{hosts} file that matches the client's
address.


The host name is followed by an optional, comma-separated list of flags,
enclosed in brackets. These flags may take the following values:


\begin{dispitems}
\ditem[\keyword{insecure}]
        Permit non-authenticated access from this machine.

\ditem[\keyword{unix-rpc}]
        Require UNIX-domain RPC authentication from this machine.  This
        simply requires that requests originate from a reserved internet
        port (i.e. the port number has to be less than 1024).  This
        option is on by default.

%% Not implemented:
\ditem[\keyword{secure-rpc}]
        Require secure RPC authentication from this machine. This has
        not been implemented yet. See Sun's documentation on Secure RPC.

\ditem[\keyword{kerberos}]
        Require Kerberos authentication on accesses from this machine.
        This has not been implemented yet.  See the MIT documentation on
        the Kerberos authentication system.

\ditem[\keyword{root\_squash}]
        \index{restrict root access@restrict \user{root} access}
        \index{access!restrict}
        This is a security feature that denies the super user on the
        specified hosts any special access rights by mapping requests
        from uid 0 on the client to uid 65534 (-2) on the server.  This
        uid should be associated with the user \user{nobody}.

\ditem[\keyword{no\_root\_squash}]
        Don't map requests from uid 0.  This option is on by default.

\ditem[\keyword{ro}]
        \index{mounting!readonly}
        \index{readonly NFS volume}
        \index{NFS!readonly volume}
        Mount file hierarchy read-only.  This option is on by default.

\ditem[\keyword{rw}]
        Mount file hierarchy read-write.

\ditem[\keyword{link\_relative}]
        Convert absolute symbolic links (where the link contents start
        with a slash) into relative links by prepending the necessary
        number of \file{../}'s to get from the directory containing the
        link to the root on the server. This option only makes sense
        when a host's entire file system is mounted, else some of the
        links might point to nowhere, or even worse, files they were
        never meant to point to.

        This option is on by default.

\ditem[\keyword{link\_absolute}]
        Leave all symbolic link as they are (the normal behavior for
        Sun-supplied NFS servers).

\ditem[\keyword{map\_identity}]
        \index{NFS!matching uids and gids}
        The \keyword{map\_identity} option tells the server to assume
        that the client uses the same uid's and gid's as the server.
        This option is on by default.

\ditem[\keyword{map\_daemon}]
        This option tells the NFS server to assume that client and
        server do not share the same uid/gid space.  \prog{nfsd} will
        then build a list mapping id's between client and server by
        querying the client's \prog{ugidd} daemon.

\end{dispitems}


\index{syslog@\prog{syslog}}
An error parsing the \file{exports} file is reported to \prog{syslogd}'s
\keyword{daemon} facility at level \keyword{notice} whenever \prog{nfsd} or
\prog{mountd} is started up.


Note that host names are obtained from the client's IP~address by
reverse mapping, so you have to have the resolver configured properly.
If you use BIND and are very security-conscious, you should enable spoof
checking in your \file{host.conf} file.



\section{The \linux{} Automounter}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{nfs.automounter}
\index{NFS!automounter}
\index{mounting!automatically}
\index{automounter}
\index{amd@\prog{amd}}

Sometimes, it is wasteful to mount all NFS volumes users might possibly
want to access; either because of the sheer number of volumes to be
mounted, or because of the time this would take at startup. A viable
alternative to this is a so-called \emph{automounter}. This is a daemon
that automatically and transparently mounts any NFS volume as needed,
and unmounts them after they have not been used for some time. One of
the clever things about an automounter is that it is able to mount a
certain volume from alternative places.  For instance, you may keep
copies of your X~programs and support files on two or three hosts, and
have all other hosts mount them via NFS.  Using an automounter, you may
specify all three of them to be mounted on \file{/usr/X386}; the
automounter will then try to mount any of these until one of the mount
attempts succeeds.


% At startup,
% it reads some so-called \emph{map files} that specify directory
% access points, along with the NFS volumes to be mounted on them.
% The automounter monitors these directories, and whenever an attempt is
% made to access one of them, or a file below, it mounts the corresponding
% NFS volume.


The automounter commonly used with \linux{} is called \prog{amd}. It
was originally written by Jan-Simon Pendry and has been ported to
\linux{} by Rick Sladkey. The current version is \prog{amd-5.3}.


Explaining \prog{amd} is beyond the scope of this chapter; for
a good manual please refer to the sources; they contain a texinfo
file with very detailed information.


\index{NFS|)}
